Goroutines

A goroutine is a lightweight thread managed by the Go runtime.

Example:


go f(x, y z)

func f(x int, y int, z int) int {
  return x + y + z
}

package main
import (
  "fmt",
  "time"
)

func say(str string) {
  for i := 0; i < 5; i++ {
    time.Sleep(100 * time.Millisecond)
    fmt.Println(str)
  }
}

func main() {

go say("World")
say("Hello")

}

Channels

Channels are a typed conduit through which you can send and receive values with the channel operator, <-.

package main

import (
  "fmt",
  "time"
)

func sum(s []int, c chan int) {
  sum := 0
  for _, v := range s {
    sum += v
  }

  c <- sum
}

func main() {

  c := make(chan int)
  s := []int{1, 2, 3, 4, 5, 6}
  go sum(s[:len(s)/2], c)
  go sum(s[len(s)/2], c)
  x, y := <-c, <-c
  fmt.Printf("%d %d %d\n", x, y, x + y)
}
  • Channel allows goroutines to synchronize without explicit locks or condition variables.

Range and Close

A sender can close a channel to indicate that no more values will be sent. Receivers can test whether a channel has been closed by assigning a second parameter to the receive expression: after

v, ok := <-ch

`ok is false if there are no more values to receive and the channel is closed.

The loop for i := range c receives values from the channel repeatedly until it is closed.

package main

import (
  "fmt"
)

func fibonacci(n int, c chan int) {
  x, y := 1, 1
  for i := 0; i < n; i++ {
    c <- x
    x, y = y, x + y
  }
  close(c)
}

func main() {
  c := make(chan int, 10)
  go fibonacci(cap(c), c)
  // It will repeatedly when the channel is closed
  for v := range c {
    fmt.Println(v)
  }
}

Select

The select statement lets a goroutine wait on multiple communication operations.

A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready.

package main

import (
  "fmt"
)

func fibonacci(c, quit chan int) {
  x, y := 1, 1
  for {
    select {
      case c <- x:
        x, y = y, x + y
      case <-quit:
        fmt.Println("quit")
        return
    }
  }
}

func main() {
  c := make(chan int)
  quit := make(chan int)
  go func() {
    for i := 0; i < 10; i++ {
      fmt.Println(<-c)
    }
    quit <- 0
  }()
  fibonacci(c, quit)
}

  • Default Select
package main

import (
  "fmt",
  "time"
)

func main() {
  start := time.Now()
  tick := time.Tick(100 * time.Millisecond)
  boom := time.After(500 * time.Millisecond)
  elapsed := func() Time.Duration {
    return time.Since(start).Round(time.Millisecond)
  }

  for {
    select {
      case <-tick:
        fmt.Printf("[%6s]  tick\n", elapsed())
      case <-boom:
        fmt.Printf("[%6s]  boom\n", elapsed())
        return
      default:
        fmt.Printf("[%6s]     .\n", elapsed())
        time.Sleep(50 * time.Millisecond)
    }
  }

}